//
//  BLEFacade.swift
//  WNLockDemo
//
//  Created by 裴威 on 30/08/2018.
//  Copyright © 2018 wunu. All rights reserved.
//

import Foundation
import CoreBluetooth

@objc protocol BLELockDelegate: NSObjectProtocol {
    @objc optional func didDiscoverDevice(_ device: BleDevice)
    @objc optional func didUpdateState(_ state: CBCentralManagerState)
}
class BLEFacade: NSObject {
    lazy private var centralManager: BluetoothManager! = BluetoothManager.getInstance()
    private(set) var configure: BLEConfigure!
    weak var delegate: BLELockDelegate?
    var currentDevice: BleDevice?
    var resultHandler: ((_ info: [String: Any], _ error: NSError?) -> Void)?
    var commandBuilder: BLECommandBuilder!
    init(configure: BLEConfigure) {
        self.configure = configure
    }
    /// 开始扫描设备
    func startScan() {
        centralManager.delegate = self
        centralManager.startScanPeripheral()
    }
    /// 停止扫描设备
    func stopScan() {
        centralManager.stopScanPeripheral()
    }
    /// 断开当前链接的设备
    func disconnectDevice() {
        centralManager.disconnectPeripheral()
    }
    
    /// 执行蓝牙指令
    ///
    /// - Parameters:
    ///   - device: 将要执行指令的设备
    ///   - command: 指令
    ///   - handler: 回调
    private func execute(device: BleDevice, command: WNLockCommamd, handler: @escaping (_ info: [String: Any], _ error: NSError?) -> Void) {
        self.commandBuilder = BLECommandBuilder(command: command)
        self.resultHandler = handler
        if let connectedPeripheral = centralManager.connectedPeripheral,
            centralManager.connected,
            connectedPeripheral.name ?? "" == device.name ?? "" {
            currentDevice = device
            currentDevice?.connectedPeripheral = connectedPeripheral
            centralManager.discoverCharacteristics()
        } else if let peripheral = device.peripheral {
            currentDevice = device
            centralManager.disconnectPeripheral()
            centralManager.connectPeripheral(peripheral)
        } else {
            resultHandler?([:], NSError(domain: "设备断开连接", code: 201, userInfo: nil))
        }
        centralManager.stopScanPeripheral()
    }
    
    /// 获取设备mac地址 和 绑定状态
    ///
    /// - Parameter handler: 回调
    func checkLock(device: BleDevice, handler: @escaping (_ info: [String: Any], _ error: NSError?) -> Void) {
        execute(device: device, command: .check, handler: handler)
    }
    
    /// 绑定锁
    ///
    /// - Parameters:
    ///   - device: 将要绑定的设备
    ///   - handler: 回调 [code: Int]
    func bindLock(device: BleDevice, basecode: UInt32, openId: UInt32, handler: @escaping (_ info: [String: Any], _ error: NSError?) -> Void) {
        execute(device: device, command: .bind(baseCode: basecode, openId: openId), handler: handler)
    }
    
    /// 解绑锁
    ///
    /// - Parameters:
    ///   - device: 将要解绑的设备
    ///   - openId: 管理员id
    ///   - basecode: 当前锁的basecode
    ///   - handler: 回调[code: Int]
    func unbindLock(device: BleDevice, openId: UInt32, basecode: UInt32, handler: @escaping (_ info: [String: Any], _ error: NSError?) -> Void) {
        execute(device: device, command: WNLockCommamd.unbind(baseCode: basecode, openId: openId), handler: handler)
    }
    
    /// 开锁
    ///
    /// - Parameters:
    ///   - device: 将要开锁的设备
    ///   - basecode: basecode
    ///   - handler: 回调[code: Int]
    func openLock(device: BleDevice, basecode: UInt32, handler: @escaping (_ info: [String: Any], _ error: NSError?) -> Void) {
        let random = UInt32.randomPrime(length: 8)
        let uint32s = xxteaEncrypt(plainValue: [0, random], k: [0,0,0,basecode])
        execute(device: device, command: WNLockCommamd.openstep1(xxetaV: uint32s)) { (info, error) in
            if let e = error {
                handler([:], e)
            } else {
                let n = Int(info["n"] as? UInt8 ?? 0)
                var A: UInt32?
                var B: UInt32?
                
                for i in 0 ... n {
                    A = basecode - UInt32(i)
                    if A!.isPrime {
                        break
                    }
                }
                for i in 0 ... n {
                    B = basecode + UInt32(i)
                    if B!.isPrime {
                        break
                    }
                }
                if let a = A, let b = B {
                    let uint32s = xxteaEncrypt(plainValue: [0, b], k: [0,0,0,a])
                    self.execute(device: device, command: WNLockCommamd.openstep2(xxetaV: uint32s), handler: handler)
                }
            }
        }
    }
    
}

extension BLEFacade: BluetoothDelegate {
    func didUpdateState(_ state: CBCentralManagerState) {
        delegate?.didUpdateState?(state)
    }
    func didDiscoverPeripheral(_ peripheral: CBPeripheral, advertisementData: [String : Any], RSSI: NSNumber) {
        let device = BleDevice()
        device.name = peripheral.name
        device.rssi = RSSI.intValue
        device.advertisementData = advertisementData
        device.peripheral = peripheral
        delegate?.didDiscoverDevice?(device)
    }
    func didConnectedPeripheral(_ connectedPeripheral: CBPeripheral) {
        currentDevice?.connectedPeripheral = connectedPeripheral
        
        print("device: \(connectedPeripheral.name ?? "none") has connected!")
    }
    func didDiscoverServices(_ peripheral: CBPeripheral) {
        if let services = peripheral.services {
            for service in services {
                print("service:" + service.uuid.uuidString)
            }
            currentDevice?.service = services.first { $0.uuid.isEqual(configure.serviceUUID) }
            centralManager.discoverCharacteristics()
        }
    }
    func didDiscoverCharacteritics(_ service: CBService) {
        if let characteritics = service.characteristics {
            currentDevice?.readCharacteritic = characteritics.first { $0.uuid.uuidString == configure.readUUID.uuidString }
            if let readCharacteritic = currentDevice?.readCharacteritic {
                centralManager.setNotification(enable: true, forCharacteristic: readCharacteritic)
            }
            currentDevice?.writeCharacteritic = characteritics.first { $0.uuid.uuidString == configure.writeUUID.uuidString }
            if let writeCharacteritic = currentDevice?.writeCharacteritic {
                let builder = BLECommandBuilder(command: .check)
                centralManager.writeValue(data: builder.getCommandData(), forCharacteristic: writeCharacteritic, type: .withResponse)
            }
        }
    }
    
    func didReadValueForCharacteristic(_ characteristic: CBCharacteristic) {
        if let value = characteristic.value {
            let info = commandBuilder.getResponseInfo(data: value)
            resultHandler?(info, nil)
        } else {
            resultHandler?([:], NSError(domain: "蓝牙未能接收到数据", code: 202, userInfo: nil))
        }
    }
    
    func didDisconnectPeripheral(_ peripheral: CBPeripheral) {
        resultHandler?([:], NSError(domain: "设备断开连接", code: 201, userInfo: nil))
    }
    
}

